// Dacris Benchmarks 6.0
// Codename 'Lyon' Build 5300
// **
// Bmark.cpp
// Defines the entry point for the Windows application.
// **
// Copyright (C) 2016 Dacris Software Inc. All Rights Reserved.
//
//-------
// BUILDS
//-------
// -- 4150 Last Borland C++ build
// -- 4410 First VC++ build, Renaissance
// -- 4900 v4.9 Final release
// -- 5005 v5.0 Final release
// -- 5160 v6.0 'Lyon' Milestone 1, VC++ 2005
// -- 5162 v6.0 Added view in browser feature (M2)
// -- 5167 v6.0 Added Excel report feature
// -- 5170 v6.0 Dynamic baseline description
// -- 5172 v6.0 Baseline information message
// -- 5175 v6.0 Added support for HTML Help
// -- 5178 v6.0 Refactored HTML navigation
// -- 5180 v6.0 Adjusted levels in header image (M3)
// -- 5182 v6.0 Fixed working directory bug
// -- 5205 v6.0 Fixed M2 bugs, Milestone 3
// -- 5270 v6.0 Fixed M3 bugs, Milestone 4
// -- 5280 v6.0 Fixed M4 bugs, RC1
// -- 5300 v6.0 Fixed RC1 bug in Crypto API (RTW)

#include "stdafx.h"
#include <windows.h>
#include <commctrl.h>
#include <malloc.h>
#include <tchar.h>
#include <intrin.h>
#include "bmark.h"
#include "webform.h"
#include "BmarkPlugins.h"

#pragma comment(linker, "\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

BmarkApp bmarkApp;

const DWORD Build = 5300;

#define HTML_FILE_NAME	"Out.html"
#define HTML_BUF_SIZE	4096

#define CSV_FILE_NAME	"Out.csv"

#define ID_SPLASHCLOSE  101

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ProgressDialogProc (hDlg, message, wParam, lParam)         *
 *                                                                          *
 *  PURPOSE    : Dialog function for the progress dialog.                   *
 *                                                                          *
 ****************************************************************************/
INT_PTR CALLBACK ProgressDialogProc (
    HWND   hDlg,
    UINT   msg,
    WPARAM wParam,
    LPARAM lParam )
{
    BOOL ret = FALSE;
    
    switch (msg)
    {
        case WM_INITDIALOG:
            ret = TRUE;
            break;

        case WM_COMMAND:
			if (LOWORD(wParam) == IDCANCEL)
			{
				// cancel all running tests
				for (int i = 0; i < bmarkApp.nPlugins; i++)
				{
					// do plugin cancellation code here
					TDllPluginFunction func = (TDllPluginFunction)GetProcAddress(bmarkApp.plugins[i].hInst, "DllPluginFunction");
					if (func != NULL)
					{
						PluginData pluginData;
						pluginData.iValue = i;
						pluginData.pValue = &bmarkApp;
						func(BMARK_CANCEL_TEST, &pluginData);
					}
				}
				bmarkApp.isTestRunning = FALSE;
                DestroyWindow (hDlg);
				ret = TRUE;
			}
            else
            {
                ret = FALSE;
            }
			break;

        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
            {
                DestroyWindow (hDlg);
                ret = TRUE;
            }
            else
            {
                ret = FALSE;
            }
            break;

            
        default:
            ret = FALSE;
            break;
    }
    
    return (INT_PTR) ret;
}

VOID GetCPUBrandString(char* lpszCPUBrandString)
{
	int CPUInfo[4] = {-1};
	unsigned nExIds, i = 0;
	char CPUBrandString[0x40];

	// gets the number of valid extended ids
	__cpuid(CPUInfo, 0x80000000);
	nExIds = CPUInfo[0];

	// Get the information associated with each extended ID.
	for (i=0x80000000; i<=nExIds; ++i)
	{
		__cpuid(CPUInfo, i);
		// Interpret the brand string
		if (i == 0x80000002)
		{
			memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
		}
		else if (i == 0x80000003)
		{
			memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
		}
		else if (i == 0x80000004)
		{
			memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
		}
	}
	//string includes manufacturer, model, and clock speed
	lstrcpy(lpszCPUBrandString, CPUBrandString);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : GetDXVersion                                               *
 *                                                                          *
 *  PURPOSE    : Get the version of DirectX installed.                      *
 *                                                                          *
 ****************************************************************************/
DWORD GetDXVersion()
{
	DWORD dwDXVersion = 0x700; //start at 7.0 or less
    HINSTANCE hD3D8DLL = NULL;
    HINSTANCE hD3D9DLL = NULL;
    HINSTANCE hD3D10DLL = NULL;
    HINSTANCE hD3D11DLL = NULL;
    HINSTANCE hD3D12DLL = NULL;
	HINSTANCE hDPNHPASTDLL = NULL;

    // Simply see if D3D8.dll exists.
    hD3D8DLL = LoadLibrary( "D3D8.DLL" );
    if( hD3D8DLL == NULL )
    {
        return dwDXVersion;
    }
	FreeLibrary(hD3D8DLL);

    // D3D8.dll exists. We must be at least DX8.0
    dwDXVersion = 0x800;

	//-------------------
    // DirectX 8.1 Checks
	//-------------------

    // Simply see if dpnhpast.dll exists.
    hDPNHPASTDLL = LoadLibrary( "dpnhpast.dll" );
    if( hDPNHPASTDLL == NULL )
    {
        return dwDXVersion;
    }
    FreeLibrary(hDPNHPASTDLL);

    // dpnhpast.dll exists. We must be at least DX8.1
    dwDXVersion = 0x801;

	//-------------------
    // DirectX 9.0 Checks
	//-------------------

    // Simply see if d3d9.dll exists.
    hD3D9DLL = LoadLibrary( "d3d9.dll" );
    if( hD3D9DLL == NULL )
    {
        return dwDXVersion;
    }
    FreeLibrary(hD3D9DLL);

    // d3d9.dll exists. We must be at least DX9.0
    dwDXVersion = 0x900;

	//--------------------
    // DirectX 10.0 Checks
	//--------------------

    // Simply see if d3d10.dll exists.
    hD3D10DLL = LoadLibrary( "d3d10.dll" );
    if( hD3D10DLL == NULL )
    {
        return dwDXVersion;
    }
    FreeLibrary(hD3D10DLL);

    // d3d10.dll exists. We must be at least DX10.0
    dwDXVersion = 0x1000;

	//--------------------
    // DirectX 11.0 Checks
	//--------------------

    // Simply see if d3d11.dll exists.
    hD3D11DLL = LoadLibrary( "d3d11.dll" );
    if( hD3D11DLL == NULL )
    {
        return dwDXVersion;
    }
    FreeLibrary(hD3D11DLL);

    // d3d11.dll exists. We must be at least DX11.0
    dwDXVersion = 0x1100;

	//--------------------
    // DirectX 12.0 Checks
	//--------------------

    // Simply see if d3d12.dll exists.
    hD3D12DLL = LoadLibrary( "d3d12.dll" );
    if( hD3D12DLL == NULL )
    {
        return dwDXVersion;
    }
    FreeLibrary(hD3D12DLL);

    // d3d12.dll exists. We must be at least DX12.0
    dwDXVersion = 0x1200;

	return dwDXVersion;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CheckSysInfoBuffer                                         *
 *                                                                          *
 *  PURPOSE    : Check internal buffers for overrun.                        *
 *                                                                          *
 ****************************************************************************/
VOID CheckSysInfoBuffer(TCHAR* lpszBuf, TCHAR* SysInfoBuf)
{
	if (lstrlen(lpszBuf) + lstrlen(SysInfoBuf) >= MAX_DESC)
	{
		MessageBox(NULL, "Buffer overrun getting system information.", "Error", MB_OK|MB_ICONINFORMATION);
		return;
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : GetSysInfo                                                 *
 *                                                                          *
 *  PURPOSE    : Get system information as plain text.                      *
 *                                                                          *
 ****************************************************************************/
VOID GetSysInfo(TCHAR* lpszBuf, DWORD nBufSize)
{
	//get SysInfo Strings here
	MEMORYSTATUSEX memstat;
	memstat.dwLength = sizeof(MEMORYSTATUSEX);
	GlobalMemoryStatusEx(&memstat);

	SYSTEM_INFO sysInfo;
	GetSystemInfo(&sysInfo);

	OSVERSIONINFO osVersionInfo;
	osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osVersionInfo);

	DWORD dwNumProcessors = sysInfo.dwNumberOfProcessors;

	DWORD dwVersion = GetVersion();
	DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
	DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
	DWORD dwBuild = 0;
	if (dwVersion < 0x80000000) {
		dwBuild = (DWORD)(HIWORD(dwVersion));
	}

	BOOL supports3DNow = IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE);
	BOOL supportsCmpXchg = IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE_DOUBLE);
	BOOL supportsMMX = IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE);
	BOOL supportsNXbit = IsProcessorFeaturePresent(PF_NX_ENABLED);
	BOOL supportsSSE = IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
	BOOL supportsSSE2 = IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
	BOOL supportsPAE = IsProcessorFeaturePresent(PF_PAE_ENABLED);

	char CPUBrandString[0x40];
	char SysInfoBuf[MAX_DESC];
	char CPUSupportsString[MAX_TITLE];
	GetCPUBrandString(CPUBrandString);

	char RootPath[MAX_TITLE];
	wsprintf(RootPath, "%c:\\", bmarkApp.settings.cDriveLetter);
	ULARGE_INTEGER ulDiskBytesAvailable;
	ULARGE_INTEGER ulDiskTotalNumberOfBytes;
	ULARGE_INTEGER ulDiskTotalNumberOfFreeBytes;
	GetDiskFreeSpaceEx(RootPath, &ulDiskBytesAvailable,
		&ulDiskTotalNumberOfBytes, &ulDiskTotalNumberOfFreeBytes);

	int diskGBTotal = (int)(ulDiskTotalNumberOfBytes.QuadPart / 1048576 / 1024);
	int diskGBFree = (int)(ulDiskTotalNumberOfFreeBytes.QuadPart / 1048576 / 1024);

	DISPLAY_DEVICE videoCardInfo;
	videoCardInfo.cb = sizeof(DISPLAY_DEVICE);
	EnumDisplayDevices(NULL, 0, &videoCardInfo, 0);

	HDC hMainDC = GetDC(bmarkApp.hMainWnd);
	int videoBpp = GetDeviceCaps(hMainDC, COLORRES);
	ReleaseDC(bmarkApp.hMainWnd, hMainDC);

	DWORD dxVersion = GetDXVersion();

	lstrcpy(CPUSupportsString, "");
	if (supports3DNow)
	{
		lstrcat(CPUSupportsString, "3DNow! ");
	}
	if (supportsCmpXchg)
	{
		lstrcat(CPUSupportsString, "Cmpxchg ");
	}
	if (supportsMMX)
	{
		lstrcat(CPUSupportsString, "MMX ");
	}
	if (supportsNXbit)
	{
		lstrcat(CPUSupportsString, "NX bit ");
	}
	if (supportsSSE)
	{
		lstrcat(CPUSupportsString, "SSE ");
	}
	if (supportsSSE2)
	{
		lstrcat(CPUSupportsString, "SSE2 ");
	}
	if (supportsPAE)
	{
		lstrcat(CPUSupportsString, "PAE");
	}

	if (nBufSize == MAX_DESC) {
		lstrcpy(lpszBuf, "");
		wsprintf(SysInfoBuf, "Windows NT %d.%d\n", dwMajorVersion, dwMinorVersion);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "CPU: %s\n", CPUBrandString);
		CheckSysInfoBuffer(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "Video: %s\n", videoCardInfo.DeviceString);
		CheckSysInfoBuffer(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "%d MB RAM\n", memstat.ullTotalPhys/1048576);
		CheckSysInfoBuffer(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "%d GB HDD\n", diskGBTotal);
		CheckSysInfoBuffer(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, SysInfoBuf);
	}
	else {
		lstrcat(lpszBuf, "ENVIRONMENT\r\n");
		wsprintf(SysInfoBuf, "Operating System: Windows NT %d.%d.%d\r\n", dwMajorVersion, dwMinorVersion, dwBuild);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "CSD Version: %s\r\n", osVersionInfo.szCSDVersion);
		lstrcat(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, "\r\n");
		lstrcat(lpszBuf, "PROCESSOR\r\n");
		wsprintf(SysInfoBuf, "Processor: %s\r\n", CPUBrandString);
		lstrcat(lpszBuf, SysInfoBuf);
		if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
			lstrcat(lpszBuf, "Processor Bits: 64\r\n");
		}
		else if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
			lstrcat(lpszBuf, "Processor Bits: 32\r\n");
		}
		wsprintf(SysInfoBuf, "Number of Processors: %d\r\n", dwNumProcessors);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "Processor Supports: %s\r\n", CPUSupportsString);
		lstrcat(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, "\r\n");
		lstrcat(lpszBuf, "MEMORY\r\n");
		wsprintf(SysInfoBuf, "Free Physical Memory: %d MB\r\n", memstat.ullAvailPhys/1048576);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "Total Physical Memory: %d MB\r\n", memstat.ullTotalPhys/1048576);
		lstrcat(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, "\r\n");
		lstrcat(lpszBuf, "HARD DISK\r\n");
		wsprintf(SysInfoBuf, "Free Disk Space: %d GB\r\n", diskGBFree);
		lstrcat(lpszBuf, SysInfoBuf);
		wsprintf(SysInfoBuf, "Total Disk Space: %d GB\r\n", diskGBTotal);
		lstrcat(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, "\r\n");
		lstrcat(lpszBuf, "VIDEO\r\n");
		wsprintf(SysInfoBuf, "Video Card: %s\r\n", videoCardInfo.DeviceString);
		lstrcat(lpszBuf, SysInfoBuf);
		lstrcat(lpszBuf, "DirectX Version: ");
		if (dxVersion <= 0x700)
		{
			lstrcat(lpszBuf, "7.0 or less\r\n");
		}
		if (dxVersion == 0x800)
		{
			lstrcat(lpszBuf, "8.0\r\n");
		}
		if (dxVersion == 0x801)
		{
			lstrcat(lpszBuf, "8.1\r\n");
		}
		if (dxVersion == 0x900)
		{
			lstrcat(lpszBuf, "9.0\r\n");
		}
		if (dxVersion == 0x1000)
		{
			lstrcat(lpszBuf, "10.0\r\n");
		}
		if (dxVersion == 0x1100)
		{
			lstrcat(lpszBuf, "11.0\r\n");
		}
		if (dxVersion == 0x1200)
		{
			lstrcat(lpszBuf, "12.0\r\n");
		}
		wsprintf(SysInfoBuf, "Bits Per Pixel: %d\r\n", videoBpp);
		lstrcat(lpszBuf, SysInfoBuf);
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ShowHTML                                                   *
 *                                                                          *
 *  PURPOSE    : Show the specified HTML in a web browser control or        *
 *               in the browser. If showInApp == TRUE, show only in app.    *
 *               If showInApp == FALSE, show in app and open in browser.    *
 *                                                                          *
 ****************************************************************************/
VOID ShowHTML(TCHAR* lpszHTML, BOOL showInApp)
{
	// show only in app
	if (showInApp == TRUE)
	{
		WebformReady(bmarkApp.hWebWnd);
		WebformSet(bmarkApp.hWebWnd, lpszHTML);
		WebformGo(bmarkApp.hWebWnd,0);
	}

	// open in default web browser
	if (showInApp == FALSE)
	{
		// Write to 'Out.html' and open in default web browser
		HANDLE hFile = CreateFile(HTML_FILE_NAME, GENERIC_WRITE,
			FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE)
		{
			DWORD dwBytesWritten;
			WriteFile(hFile, lpszHTML, lstrlen(lpszHTML), &dwBytesWritten, NULL);
			CloseHandle(hFile);

			// Open in default web browser
			ShellExecute(bmarkApp.hMainWnd,
				NULL, HTML_FILE_NAME, NULL, NULL, SW_SHOWDEFAULT);
		}
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ShowWelcomeHTML                                            *
 *                                                                          *
 *  PURPOSE    : Show the HTML for the welcome screen.                      *
 *                                                                          *
 ****************************************************************************/
VOID ShowWelcomeHTML(BOOL showInApp)
{
	TCHAR* lpszHTML = (TCHAR*)malloc(HTML_BUF_SIZE);
	ZeroMemory(lpszHTML, HTML_BUF_SIZE);
	lstrcpy(lpszHTML, _T("<html><head><style>* { font-family: Verdana; }</style></head><body><form>\n")
		_T("<h3>Welcome to Dacris Benchmarks</h3>\n")
		_T("<div id='label'>Use the menu to navigate and run tests.<div>\n")
		_T("</form></body></html>\n"));
	ShowHTML(lpszHTML, showInApp);
	free(lpszHTML);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ShowResultsHTML                                            *
 *                                                                          *
 *  PURPOSE    : Show the HTML for test results.                            *
 *                                                                          *
 ****************************************************************************/
VOID ShowResultsHTML(BOOL showInApp)
{
	TCHAR* lpszHTML = (TCHAR*)malloc(HTML_BUF_SIZE);
	ZeroMemory(lpszHTML, HTML_BUF_SIZE);
	lstrcpy(lpszHTML, "<html><head><title>Test Results</title><style>* { font-family: Verdana; } tr.hdr td { border-bottom: 1px solid #999; font-weight: bold; } td { padding-right: 12px; }</style></head><body><h3>Test Report</h3>\r\n");
	lstrcat(lpszHTML, "<table style=\"border: 1px solid #999;\">\r\n");
	lstrcat(lpszHTML, "<tr class=\"hdr\"><td>Test</td><td>Result</td><td>Baseline Result</td></tr>\r\n");
	//organize by current baseline's test results
	for (int i = 0; i < bmarkApp.currentBaseline.nResults; i++)
	{
		char* titleCur = bmarkApp.currentBaseline.results[i].title;
		int refIdx = -1;
		//find comparable reference result
		for (int j = 0; j < bmarkApp.referenceBaseline.nResults; j++)
		{
			char* titleRef = bmarkApp.referenceBaseline.results[j].title;
			if(!lstrcmp(titleCur, titleRef))
			{
				refIdx = j;
				break;
			}
		}
		char* unitCur = bmarkApp.currentBaseline.results[i].unit;
		int resultCur = (int)bmarkApp.currentBaseline.results[i].result;
		char* unitRef = unitCur;
		int resultRef = 0;
		if (refIdx >= 0 && refIdx < bmarkApp.referenceBaseline.nResults)
		{
			unitRef = bmarkApp.referenceBaseline.results[refIdx].unit;
			resultRef = (int)bmarkApp.referenceBaseline.results[refIdx].result;
		}
		char resultCurStr[MAX_UNIT];
		char resultRefStr[MAX_UNIT];
		wsprintf(resultCurStr, "%d", resultCur);
		wsprintf(resultRefStr, "%d", resultRef);
		lstrcat(lpszHTML, "<tr><td>");
		lstrcat(lpszHTML, titleCur);
		lstrcat(lpszHTML, "</td><td>");
		lstrcat(lpszHTML, resultCurStr);
		lstrcat(lpszHTML, " ");
		lstrcat(lpszHTML, unitCur);
		lstrcat(lpszHTML, "</td><td>");
		lstrcat(lpszHTML, resultRefStr);
		lstrcat(lpszHTML, " ");
		lstrcat(lpszHTML, unitRef);
		lstrcat(lpszHTML, "</td></tr>\r\n");
	}
	lstrcat(lpszHTML, "</table></body></html>");
	ShowHTML(lpszHTML, showInApp);
	free(lpszHTML);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ShowSysInfoHTML                                            *
 *                                                                          *
 *  PURPOSE    : Show the HTML for system information.                      *
 *                                                                          *
 ****************************************************************************/
VOID ShowSysInfoHTML(BOOL showInApp)
{
	TCHAR* lpszHTML = (TCHAR*)malloc(HTML_BUF_SIZE);
	TCHAR* lpszSysInfo = (TCHAR*)malloc(HTML_BUF_SIZE);
	ZeroMemory(lpszHTML, HTML_BUF_SIZE);
	ZeroMemory(lpszSysInfo, HTML_BUF_SIZE);
	GetSysInfo(lpszSysInfo, HTML_BUF_SIZE);
	lstrcpy(lpszHTML, "<html><head><title>System Information</title><style>* { font-family: Verdana; }</style></head><body><h3>System Information</h3><pre>\r\n");
	lstrcat(lpszHTML, lpszSysInfo);
	lstrcat(lpszHTML, "</pre></body></html>");
	ShowHTML(lpszHTML, showInApp);
	free(lpszSysInfo);
	free(lpszHTML);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ShowResultsExcel                                           *
 *                                                                          *
 *  PURPOSE    : Show the CSV for test results.                             *
 *                                                                          *
 ****************************************************************************/
VOID ShowResultsExcel()
{
	TCHAR* lpszExcel = (TCHAR*)malloc(HTML_BUF_SIZE);
	ZeroMemory(lpszExcel, HTML_BUF_SIZE);
	lstrcat(lpszExcel, "Test,Result,Unit,Baseline Result,Baseline Unit\r\n");
	//organize by current baseline's test results
	for (int i = 0; i < bmarkApp.currentBaseline.nResults; i++)
	{
		char* titleCur = bmarkApp.currentBaseline.results[i].title;
		int refIdx = -1;
		//find comparable reference result
		for (int j = 0; j < bmarkApp.referenceBaseline.nResults; j++)
		{
			char* titleRef = bmarkApp.referenceBaseline.results[j].title;
			if(!lstrcmp(titleCur, titleRef))
			{
				refIdx = j;
				break;
			}
		}
		char* unitCur = bmarkApp.currentBaseline.results[i].unit;
		int resultCur = (int)bmarkApp.currentBaseline.results[i].result;
		char* unitRef = unitCur;
		int resultRef = 0;
		if (refIdx >= 0 && refIdx < bmarkApp.referenceBaseline.nResults)
		{
			unitRef = bmarkApp.referenceBaseline.results[refIdx].unit;
			resultRef = (int)bmarkApp.referenceBaseline.results[refIdx].result;
		}
		char resultCurStr[MAX_UNIT];
		char resultRefStr[MAX_UNIT];
		wsprintf(resultCurStr, "%d", resultCur);
		wsprintf(resultRefStr, "%d", resultRef);
		lstrcat(lpszExcel, titleCur);
		lstrcat(lpszExcel, ",");
		lstrcat(lpszExcel, resultCurStr);
		lstrcat(lpszExcel, ",");
		lstrcat(lpszExcel, unitCur);
		lstrcat(lpszExcel, ",");
		lstrcat(lpszExcel, resultRefStr);
		lstrcat(lpszExcel, ",");
		lstrcat(lpszExcel, unitRef);
		lstrcat(lpszExcel, "\r\n");
	}
	// show text in Excel
	// Write to 'Out.csv' and open in Excel or equivalent app
	HANDLE hFile = CreateFile(CSV_FILE_NAME, GENERIC_WRITE,
		FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwBytesWritten;
		WriteFile(hFile, lpszExcel, lstrlen(lpszExcel), &dwBytesWritten, NULL);
		CloseHandle(hFile);

		// Open in Excel or equivalent app
		ShellExecute(bmarkApp.hMainWnd,
			NULL, CSV_FILE_NAME, NULL, NULL, SW_SHOWDEFAULT);
	}
	free(lpszExcel);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : AppMessageFunction ()                                 *
 *                                                                          *
 *  PURPOSE    : Receive a message from plugin DLL.                         *
 *                                                                          *
 ****************************************************************************/
void AppMessageFunction()
{
	//TODO: Implement this
	// check pData->iValue for message id
	PluginData* pData = (PluginData*)(GetPluginApp()->pValue);
	int iMessageId = pData->iValue;
	if (iMessageId == BMARK_REG_NAV) {
		// our variable goes out of scope so we must make a local copy
		// append to list of registered plugins
		bmarkApp.navCount++;
		bmarkApp.plugins[bmarkApp.navCount - 1].nav.iOrdinal = ((BmarkNav*)(pData->pValue))->iOrdinal;
		bmarkApp.plugins[bmarkApp.navCount - 1].nav.cbTitle = ((BmarkNav*)(pData->pValue))->cbTitle;
		lstrcpy(bmarkApp.plugins[bmarkApp.navCount - 1].nav.lpszTitle, ((BmarkNav*)(pData->pValue))->lpszTitle);
		HWND hwPluginLabel = GetDlgItem(bmarkApp.hStartupDlg, 101);
		TCHAR lpszBuffer[MAX_PATH];
		wsprintf(lpszBuffer, "Attaching plugin '%s'...", bmarkApp.plugins[bmarkApp.navCount - 1].nav.lpszTitle);
		SetWindowText(hwPluginLabel, lpszBuffer);
	}
	else if (iMessageId == BMARK_REG_RESULT) {
		BmarkResult* pResult = (BmarkResult*)pData->pValue;
		// check if a result by same title and unit already exists
		BOOL bAlreadyExists = FALSE;
		for (int i = 0; i < bmarkApp.currentBaseline.nResults; i++)
		{
			if(lstrcmp(bmarkApp.currentBaseline.results[i].title, pResult->title) == 0 &&
				lstrcmp(bmarkApp.currentBaseline.results[i].unit, pResult->unit) == 0)
			{
				bAlreadyExists = TRUE;
			}
		}
		if (!bAlreadyExists)
		{
			bmarkApp.currentBaseline.nResults++;
			lstrcpy(bmarkApp.currentBaseline.results[bmarkApp.currentBaseline.nResults - 1].title, pResult->title);
			lstrcpy(bmarkApp.currentBaseline.results[bmarkApp.currentBaseline.nResults - 1].unit, pResult->unit);
		}
	}
	else if (iMessageId == BMARK_SHOW_PROGRESS) {
		if (!IsWindow(bmarkApp.hProgressDlg))
		{
			/* Bring up the Progress dialog box */
			bmarkApp.hProgressDlg = CreateDialog (bmarkApp.hInst,
				TEXT("ProgressDlg"),
				bmarkApp.hMainWnd,
				ProgressDialogProc);

			if (bmarkApp.hProgressDlg != NULL)
			{
				ShowWindow(bmarkApp.hStartupDlg, SW_SHOW);
				UpdateWindow(bmarkApp.hStartupDlg);
			}
		}
	}
	else if (iMessageId == BMARK_HIDE_PROGRESS) {
		if (bmarkApp.hProgressDlg != NULL)
		{
			SendMessage(bmarkApp.hProgressDlg, WM_CLOSE, 0, 0);
			bmarkApp.hProgressDlg = NULL;
		}
	}
	else if (iMessageId == BMARK_SET_PROGRESS) {
		PluginData* progressData = (PluginData*)pData->pValue;
		HWND hwProgress = GetDlgItem(bmarkApp.hProgressDlg, 1001);
		SendMessage(hwProgress, PBM_SETPOS, progressData->iValue, 0);
	}
	else if (iMessageId == BMARK_SET_RESULT) {
		BmarkResult* pResult = (BmarkResult*)pData->pValue;
		for (int i = 0; i < bmarkApp.currentBaseline.nResults; i++)
		{
			//search by title
			if(!lstrcmp(bmarkApp.currentBaseline.results[i].title, pResult->title))
			{
				//set result in baseline
				bmarkApp.currentBaseline.results[i].result = pResult->result;
				lstrcpy(bmarkApp.currentBaseline.results[i].unit, pResult->unit);
			}
		}

		PluginData pluginData;
		pluginData.iValue = BMARK_NAV_RESULTS;
		pluginData.pValue = NULL;
		AppMessage(&(bmarkApp.appData), &pluginData);

		TCHAR lpszBuffer[120];
		wsprintf(lpszBuffer, "Result: %d %s", (int)pResult->result, pResult->unit);
		MessageBox(NULL, lpszBuffer, pResult->title, MB_OK|MB_ICONINFORMATION);

		bmarkApp.isTestRunning = FALSE;
	}
	else if (iMessageId == BMARK_NAV_WELCOME) {
		ShowWelcomeHTML(TRUE);
	}
	else if (iMessageId == BMARK_NAV_RESULTS) {
		ShowResultsHTML(TRUE);
	}
	else if (iMessageId == BMARK_NAV_SYSINFO) {
		ShowSysInfoHTML(TRUE);
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : AboutDialogProc (hDlg, message, wParam, lParam)            *
 *                                                                          *
 *  PURPOSE    : Dialog function for the About menu... dialog.              *
 *                                                                          *
 ****************************************************************************/
INT_PTR CALLBACK AboutDialogProc (
    HWND   hDlg,
    UINT   msg,
    WPARAM wParam,
    LPARAM lParam )
{
    BOOL ret = FALSE;
	HKEY hkCurVer;
	DWORD dwSize;
	char szBuf[MAX_DESC];

    switch (msg)
    {
        case WM_INITDIALOG:
            ret = TRUE;
			RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion"), &hkCurVer);
			dwSize = MAX_DESC;
			RegQueryValueEx(hkCurVer, "ProductName", NULL, NULL, (LPBYTE)szBuf, &dwSize);
			SetWindowText(GetDlgItem(hDlg, 91), szBuf);
			dwSize = MAX_DESC;
			if (RegQueryValueEx(hkCurVer, "RegisteredOwner", NULL, NULL, (LPBYTE)szBuf, &dwSize) == ERROR_SUCCESS)
			{
				SetWindowText(GetDlgItem(hDlg, 93), szBuf);
			}
			dwSize = MAX_DESC;
			if (RegQueryValueEx(hkCurVer, "RegisteredOrganization", NULL, NULL, (LPBYTE)szBuf, &dwSize) == ERROR_SUCCESS)
			{
				SetWindowText(GetDlgItem(hDlg, 94), szBuf);
			}
			RegCloseKey(hkCurVer);
			wsprintf(szBuf, "Codename 'Lyon' RTW (Build %d)", Build);
			SetWindowText(GetDlgItem(hDlg, 103), szBuf);
			break;

        case WM_COMMAND:
            // LOWORD added for portability
            if (LOWORD(wParam) == IDOK)
            {
                EndDialog (hDlg, 0);
                ret = TRUE;
            }
            else
            {
                ret = FALSE;
            }
            break;

        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
            {
                EndDialog (hDlg, 0);
                ret = TRUE;
            }
            else
            {
                ret = FALSE;
            }
            break;

            
        default:
            ret = FALSE;
            break;
    }
    
    return (INT_PTR) ret;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : OptionsDialogProc (hDlg, message, wParam, lParam)          *
 *                                                                          *
 *  PURPOSE    : Dialog function for the Options dialog.                    *
 *                                                                          *
 ****************************************************************************/
INT_PTR CALLBACK OptionsDialogProc (
    HWND   hDlg,
    UINT   msg,
    WPARAM wParam,
    LPARAM lParam )
{
    BOOL ret = FALSE;
	TCHAR szTestDuration[12];
	TCHAR szNumPasses[12];
	HWND hwTestDuration;
	HWND hwTestNumPasses;
	HWND hwDriveLetters;
	DWORD cbBufferLength = MAX_PATH;
	DWORD dwActualLength = 0;
	TCHAR lpszBuffer[MAX_PATH];
	TCHAR cDriveLetters[30];
	DWORD nDriveLetters = 0;
	LRESULT itemIndex = 0;
    
    switch (msg)
    {
        case WM_INITDIALOG:
			hwTestDuration = GetDlgItem(hDlg, 300);
			hwTestNumPasses = GetDlgItem(hDlg, 301);
			hwDriveLetters = GetDlgItem(hDlg, 302);

			wsprintf(szTestDuration, "%d", bmarkApp.settings.iTestDuration);
			SetWindowText(hwTestDuration, szTestDuration);

			wsprintf(szNumPasses, "%d", bmarkApp.settings.iNumPasses);
			SetWindowText(hwTestNumPasses, szNumPasses);

			itemIndex = 0;
			dwActualLength = GetLogicalDriveStrings(cbBufferLength, lpszBuffer);
			for (DWORD i = 0; i < dwActualLength; i++)
			{
				if (lpszBuffer[i] >= 'A' && lpszBuffer[i] <= 'Z' ||
					lpszBuffer[i] >= 'a' && lpszBuffer[i] <= 'z')
				{
					cDriveLetters[nDriveLetters] = lpszBuffer[i];
					nDriveLetters++;
				}
			}
			for (DWORD k = 0; k < nDriveLetters; k++)
			{
				wsprintf(lpszBuffer, "%c:\\", cDriveLetters[k]);
				if (GetDriveType(lpszBuffer) != DRIVE_CDROM)
				{
					SendMessage(hwDriveLetters, CB_ADDSTRING, 0, (LPARAM)lpszBuffer);
					if (lpszBuffer[0] == bmarkApp.settings.cDriveLetter)
					{
						SendMessage(hwDriveLetters, CB_SETCURSEL, itemIndex, 0);
					}
					itemIndex++;
				}
			}
			if (itemIndex == 0)
			{
				MessageBox(hDlg, "No read/write drives were found. CD-ROM drives are not supported.", "Error", MB_OK|MB_ICONINFORMATION);
			}

			ret = TRUE;
            break;

        case WM_COMMAND:
            // LOWORD added for portability
            if (LOWORD(wParam) == IDOK)
            {
				// Set settings
				hwTestDuration = GetDlgItem(hDlg, 300);
				hwTestNumPasses = GetDlgItem(hDlg, 301);
				hwDriveLetters = GetDlgItem(hDlg, 302);
				
				SendMessage(hwTestDuration, WM_GETTEXT, 12, (LPARAM)szTestDuration);
				sscanf_s(szTestDuration, "%d", &bmarkApp.settings.iTestDuration);
				if (bmarkApp.settings.iTestDuration < 5 || bmarkApp.settings.iTestDuration > 180) {
					MessageBox(hDlg, "Please set test duration between 5 and 180 seconds. Defaulting to 10.", "Validation Error", MB_OK|MB_ICONINFORMATION);
					bmarkApp.settings.iTestDuration = 10;
				}

				SendMessage(hwTestNumPasses, WM_GETTEXT, 12, (LPARAM)szNumPasses);
				sscanf_s(szNumPasses, "%d", &bmarkApp.settings.iNumPasses);
				if (bmarkApp.settings.iNumPasses < 1 || bmarkApp.settings.iNumPasses > 5) {
					MessageBox(hDlg, "Please set number of passes between 1 and 5. Defaulting to 1.", "Validation Error", MB_OK|MB_ICONINFORMATION);
					bmarkApp.settings.iNumPasses = 1;
				}
                
				itemIndex = SendMessage(hwDriveLetters, CB_GETCURSEL, 0, 0);
				if (itemIndex >= 0) {
					SendMessage(hwDriveLetters, CB_GETLBTEXT, itemIndex, (LPARAM)lpszBuffer);
					bmarkApp.settings.cDriveLetter = lpszBuffer[0];
				}
				else {
					bmarkApp.settings.cDriveLetter = 'C';
				}

				EndDialog (hDlg, 0);
                ret = TRUE;
            }
			else if (LOWORD(wParam) == IDCANCEL)
			{
				EndDialog (hDlg, 1);
				ret = TRUE;
			}
            else
            {
                ret = FALSE;
            }
            break;

        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
            {
                EndDialog (hDlg, 1);
                ret = TRUE;
            }
            else
            {
                ret = FALSE;
            }
            break;

            
        default:
            ret = FALSE;
            break;
    }
    
    return (INT_PTR) ret;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ValidateKey (szKeyBuf)                                     *
 *                                                                          *
 *  PURPOSE    : Validation function for activation keys.                   *
 *                                                                          *
 ****************************************************************************/
BOOL ValidateKey(char* szKeyBuf)
{
	BOOL isValid[4];
	int a, b, c, d;
	a = b = c = d = 0;
	sscanf_s(szKeyBuf, "%04x-%04x-%04x-%04x", &a, &b, &c, &d);
	isValid[0] = isValid[1] = isValid[2] = isValid[3] = FALSE;
	if (a % 4 == 0 && a >= 0x1a00 && a <= 0x7fff)
		isValid[0] = TRUE;
	if (b % 4 == 1 && b >= 0x1a00 && b <= 0x7fff)
		isValid[1] = TRUE;
	if (c % 4 == 0 && c >= 0x1a00 && c <= 0x7fff)
		isValid[2] = TRUE;
	if (d % 4 == 1 && d >= 0x1a00 && d <= 0x7fff)
		isValid[3] = TRUE;
	return isValid[0] && isValid[1] && isValid[2] && isValid[3];
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ActivationDialogProc (hDlg, message, wParam, lParam)       *
 *                                                                          *
 *  PURPOSE    : Dialog function for the Activation dialog.                 *
 *                                                                          *
 ****************************************************************************/
INT_PTR CALLBACK ActivationDialogProc (
    HWND   hDlg,
    UINT   msg,
    WPARAM wParam,
    LPARAM lParam )
{
    BOOL ret = FALSE;
	HWND hwRadio1 = NULL;
	char szKeyBuf[KEY_LENGTH];
    
    switch (msg)
    {
        case WM_INITDIALOG:
			hwRadio1 = GetDlgItem(hDlg, 300);
			SendMessage(hwRadio1, BM_SETCHECK, BST_CHECKED, 0);
			SetDlgItemText(hDlg, 200, bmarkApp.settings.activationKey);
            ret = TRUE;
            break;

        case WM_COMMAND:
            // LOWORD added for portability
            if (LOWORD(wParam) == IDOK)
            {
				GetDlgItemText(hDlg, 200, szKeyBuf, KEY_LENGTH);
				if (!ValidateKey(szKeyBuf))
				{
					MessageBox(NULL, "An invalid activation key was entered", "Error", MB_ICONINFORMATION|MB_OK);
				}
				else
				{
					MessageBox(NULL, "You have successfully activated this product.", "Success", MB_OK|MB_ICONINFORMATION);
					lstrcpy(bmarkApp.settings.activationKey, szKeyBuf);
				}
                EndDialog (hDlg, 0);
                ret = TRUE;
            }
			else if (LOWORD(wParam) == IDCANCEL)
			{
				EndDialog (hDlg, 1);
				ret = TRUE;
			}
            else
            {
                ret = FALSE;
            }
            break;

        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
            {
                EndDialog (hDlg, 1);
                ret = TRUE;
            }
            else
            {
                ret = FALSE;
            }
            break;

            
        default:
            ret = FALSE;
            break;
    }
    
    return (INT_PTR) ret;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : SaveBaseline ()                                            *
 *                                                                          *
 *  PURPOSE    : Saves current baseline data to a file.                     *
 *                                                                          *
 ****************************************************************************/
VOID SaveBaseline(TCHAR* lpszFileName)
{
	HANDLE hFile = CreateFile(lpszFileName, GENERIC_WRITE,
		FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwBytesWritten;
		WriteFile(hFile, &bmarkApp.currentBaseline, sizeof(BmarkBaseline), &dwBytesWritten, NULL);
		CloseHandle(hFile);
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : AssignBaseline (BOOL)                                      *
 *                                                                          *
 *  PURPOSE    : Assigns the specified baseline to reference or current.    *
 *                                                                          *
 ****************************************************************************/
VOID AssignBaseline(BmarkBaseline baseline, DWORD dwBytesRead, BOOL asRef)
{
	// assign only if format and version is OK
	if (baseline.version.iMajor == bmarkApp.version.iMajor
		&& baseline.version.iMinor == bmarkApp.version.iMinor
		&& dwBytesRead == sizeof(BmarkBaseline))
	{
		if (asRef == TRUE)
		{
			bmarkApp.referenceBaseline = baseline;
		}
		else
		{
			bmarkApp.currentBaseline = baseline;
		}
	}
	else 
	{
		MessageBox(NULL, "The baseline being loaded is not in a valid format.", "Error", MB_OK|MB_ICONINFORMATION);
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : LoadBaselineAsReference ()                                 *
 *                                                                          *
 *  PURPOSE    : Loads reference baseline from a file.                      *
 *                                                                          *
 ****************************************************************************/
VOID LoadBaselineAsReference(TCHAR* lpszFileName)
{
	HANDLE hFile = CreateFile(lpszFileName, GENERIC_READ,
		FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwBytesRead;
		BmarkBaseline baseline;
		ReadFile(hFile, &baseline, sizeof(BmarkBaseline), &dwBytesRead, NULL);
		CloseHandle(hFile);
		AssignBaseline(baseline, dwBytesRead, TRUE);
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : LoadBaselineAsCurrent ()                                   *
 *                                                                          *
 *  PURPOSE    : Loads current results from a file.                         *
 *                                                                          *
 ****************************************************************************/
VOID LoadBaselineAsCurrent(TCHAR* lpszFileName)
{
	HANDLE hFile = CreateFile(lpszFileName, GENERIC_READ,
		FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwBytesRead;
		BmarkBaseline baseline;
		ReadFile(hFile, &baseline, sizeof(BmarkBaseline), &dwBytesRead, NULL);
		CloseHandle(hFile);
		AssignBaseline(baseline, dwBytesRead, FALSE);
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : GetFileName ()                                             *
 *                                                                          *
 *  PURPOSE    : Gets the file name from a given path.                      *
 *                                                                          *
 ****************************************************************************/
VOID GetFileName(TCHAR* lpszFullPath, TCHAR* lpszBuffer)
{
	int k = 0;
	lpszBuffer[0] = 0;
	for (int i = 0; i <= lstrlen(lpszFullPath); i++)
	{
		if (lpszFullPath[i] == '\\')
			k = -1;
		if (k >= 0)
		{
			lpszBuffer[k] = lpszFullPath[i];
		}
		k++;
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : BaselineDialogProc (hDlg, message, wParam, lParam)         *
 *                                                                          *
 *  PURPOSE    : Dialog function for the Baselines dialog.                  *
 *                                                                          *
 ****************************************************************************/
INT_PTR CALLBACK BaselineDialogProc (
    HWND   hDlg,
    UINT   msg,
    WPARAM wParam,
    LPARAM lParam )
{
    BOOL ret = FALSE;
	LRESULT itemIndex = 0;
	HWND hwBaselineFiles;
	TCHAR lpszBuffer[MAX_PATH];
	TCHAR lpszOpenFileBuffer[MAX_PATH];
	TCHAR lpszWorkingDir[MAX_PATH];
    
    switch (msg)
    {
        case WM_INITDIALOG:
			hwBaselineFiles = GetDlgItem(hDlg, 300);
			
			for (int i = 0; i < bmarkApp.settings.nBaselineFiles; i++)
			{
				GetFileName(bmarkApp.settings.baselineFiles[i].szFilename, lpszBuffer);
				SendMessage(hwBaselineFiles, CB_ADDSTRING, 0, (LPARAM)lpszBuffer);
			}
			if (bmarkApp.settings.iDefaultBaseline >= 0)
			{
				SendMessage(hwBaselineFiles, CB_SETCURSEL, bmarkApp.settings.iDefaultBaseline, 0);
				LoadBaselineAsReference(bmarkApp.settings.baselineFiles[bmarkApp.settings.iDefaultBaseline].szFilename);
			}

			ret = TRUE;
            break;

        case WM_COMMAND:
            // LOWORD added for portability
            if (LOWORD(wParam) == IDOK)
            {
				hwBaselineFiles = GetDlgItem(hDlg, 300);
				itemIndex = SendMessage(hwBaselineFiles, CB_GETCURSEL, 0, 0);
				if (itemIndex >= 0) {
					bmarkApp.settings.iDefaultBaseline = (int)itemIndex;
					LoadBaselineAsReference(bmarkApp.settings.baselineFiles[itemIndex].szFilename);
				}
				else {
					bmarkApp.settings.iDefaultBaseline = -1;
				}
				PluginData pluginData;
				pluginData.iValue = BMARK_NAV_RESULTS;
				pluginData.pValue = NULL;
				AppMessage(&(bmarkApp.appData), &pluginData);

				EndDialog (hDlg, 1);
                ret = TRUE;
            }
			else if(LOWORD(wParam) == 300)
			{
				int notificationCode = (int)HIWORD(wParam);
				if (notificationCode == CBN_SELCHANGE)
				{
					hwBaselineFiles = (HWND)lParam;
					itemIndex = SendMessage(hwBaselineFiles, CB_GETCURSEL, 0, 0);
					if (itemIndex >= 0) {
						bmarkApp.settings.iDefaultBaseline = (int)itemIndex;
						LoadBaselineAsReference(bmarkApp.settings.baselineFiles[itemIndex].szFilename);
					}
					else {
						bmarkApp.settings.iDefaultBaseline = -1;
					}
				}
			}
			else if(LOWORD(wParam) == 103)
			{
				//save current baseline
				OPENFILENAME ofn;
				ZeroMemory(&ofn, sizeof(OPENFILENAME));
				ZeroMemory(lpszBuffer, MAX_PATH);
				ZeroMemory(lpszWorkingDir, MAX_PATH);
				GetCurrentDirectory(MAX_PATH, lpszWorkingDir);
				ofn.lStructSize = sizeof(OPENFILENAME);
				ofn.hwndOwner = hDlg;
				ofn.hInstance = bmarkApp.hInst;
				ofn.lpstrFile = lpszBuffer;
				ofn.nMaxFile = MAX_PATH;
				ofn.lpstrTitle = "Save Baseline";
				ofn.lpstrFilter = "Baselines (*.blx)\0*.blx\0";
				ofn.lpstrDefExt = "blx";
				if (GetSaveFileName(&ofn))
				{
					SaveBaseline(ofn.lpstrFile);
				}
				//restore current directory
				SetCurrentDirectory(lpszWorkingDir);
			}
			else if(LOWORD(wParam) == 104)
			{
				//load existing baseline
				if (bmarkApp.settings.nBaselineFiles
					>= MAX_BASELINES)
				{
					MessageBox(NULL, "Maximum 10 baselines are allowed. Unload some baselines to free up space.", "Baseline Limit", MB_OK|MB_ICONINFORMATION);
					return FALSE;
				}
				OPENFILENAME ofn;
				ZeroMemory(&ofn, sizeof(OPENFILENAME));
				ZeroMemory(lpszOpenFileBuffer, MAX_PATH);
				ZeroMemory(lpszWorkingDir, MAX_PATH);
				GetCurrentDirectory(MAX_PATH, lpszWorkingDir);
				ofn.lStructSize = sizeof(OPENFILENAME);
				ofn.hwndOwner = hDlg;
				ofn.hInstance = bmarkApp.hInst;
				ofn.lpstrFile = lpszOpenFileBuffer;
				ofn.nMaxFile = MAX_PATH;
				ofn.lpstrTitle = "Load Baseline";
				ofn.lpstrFilter = "Baselines (*.blx)\0*.blx\0";
				ofn.lpstrDefExt = "blx";
				if (GetOpenFileName(&ofn))
				{
					hwBaselineFiles = GetDlgItem(hDlg, 300);
					bmarkApp.settings.nBaselineFiles++;
					lstrcpy(bmarkApp.settings
						.baselineFiles[bmarkApp
						.settings.nBaselineFiles - 1].szFilename, 
						ofn.lpstrFile);
					bmarkApp.settings.iDefaultBaseline = bmarkApp
						.settings.nBaselineFiles - 1;
					GetFileName(ofn.lpstrFile, lpszBuffer);
					SendMessage(hwBaselineFiles, CB_ADDSTRING, 0, (LPARAM)lpszBuffer);
					SendMessage(hwBaselineFiles, CB_SETCURSEL,
						bmarkApp.settings.iDefaultBaseline, 0);
					LoadBaselineAsReference(ofn.lpstrFile);
				}
				//restore current directory
				SetCurrentDirectory(lpszWorkingDir);
			}
			else if(LOWORD(wParam) == 105)
			{
				//unload selected baseline
				hwBaselineFiles = GetDlgItem(hDlg, 300);
				if (bmarkApp.settings.iDefaultBaseline >= 0)
				{
					SendMessage(hwBaselineFiles, CB_DELETESTRING, bmarkApp.settings.iDefaultBaseline, 0);
					//rebuild list of files
					for (int i = bmarkApp.settings.iDefaultBaseline; i < bmarkApp.settings.nBaselineFiles - 1; i++)
					{
						lstrcpy(bmarkApp.settings.baselineFiles[i].szFilename,
							bmarkApp.settings.baselineFiles[i + 1].szFilename);
					}
					if (bmarkApp.settings.nBaselineFiles > 0)
					{
						bmarkApp.settings.nBaselineFiles--;
					}
					if (bmarkApp.settings.iDefaultBaseline >= bmarkApp.settings.nBaselineFiles)
					{
						bmarkApp.settings.iDefaultBaseline = -1;
					}
					SendMessage(hwBaselineFiles, CB_SETCURSEL,
						bmarkApp.settings.iDefaultBaseline, 0);
					ZeroMemory(&bmarkApp.referenceBaseline, sizeof(BmarkBaseline));
				}
			}
			else if(LOWORD(wParam) == 106)
			{
				if (bmarkApp.settings.iDefaultBaseline >= 0)
				{
					MessageBox(NULL, bmarkApp.referenceBaseline.description, "Information", MB_OK|MB_ICONINFORMATION);
				}
				else
				{
					MessageBox(NULL, "Information is unavailable. Please select a baseline for more information.", "No Information", MB_OK|MB_ICONINFORMATION);
				}
			}
            else
            {
                ret = FALSE;
            }
            break;

        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
            {
                EndDialog (hDlg, 1);
                ret = TRUE;
            }
            else
            {
                ret = FALSE;
            }
            break;

            
        default:
            ret = FALSE;
            break;
    }
    
    return (INT_PTR) ret;
}

/* ************************************************************** */
// GetLastWriteTime - Retrieves the last-write time and converts
//                    the time to a string
//
// Return value - TRUE if successful, FALSE otherwise
// hFile      - Valid file handle
// lpszString - Pointer to buffer to receive string
/* ************************************************************** */
BOOL GetLastWriteTime(HANDLE hFile, LPTSTR lpszString)
{
    FILETIME ftCreate, ftAccess, ftWrite;
    SYSTEMTIME stUTC, stLocal;

    // Retrieve the file times for the file.
    if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
        return FALSE;

    // Convert the last-write time to local time.
    FileTimeToSystemTime(&ftWrite, &stUTC);
    SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

    // Build a string showing the date and time.
    wsprintf(lpszString, TEXT("%02d/%02d/%d"),
        stLocal.wMonth, stLocal.wDay, stLocal.wYear);

    return TRUE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : StartupDialogProc (hDlg, message, wParam, lParam)          *
 *                                                                          *
 *  PURPOSE    : Dialog function for the startup dialog.                    *
 *                                                                          *
 ****************************************************************************/
INT_PTR CALLBACK StartupDialogProc (
    HWND   hDlg,
    UINT   msg,
    WPARAM wParam,
    LPARAM lParam )
{
    BOOL ret = FALSE;
	HANDLE hFile = NULL;
	char szBuf[MAX_DESC];
	char szDateBuf[MAX_TITLE];
	char szFileName[MAX_PATH];
    
    switch (msg)
    {
        case WM_INITDIALOG:
			if (GetModuleFileName(bmarkApp.hInst, szFileName, MAX_PATH) == 0)
			{
				wsprintf(szBuf, "Error %d getting module file name\r\n", GetLastError());
				OutputDebugString(szBuf);
			}
			else
			{
				hFile = CreateFile(szFileName, GENERIC_READ,
					FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
				if (hFile != INVALID_HANDLE_VALUE)
				{
					if (GetLastWriteTime(hFile, szDateBuf) == TRUE)
					{
						wsprintf(szBuf, "Build Date: %s", szDateBuf);
						SetWindowText(GetDlgItem(hDlg, 102), szBuf);
					}
					CloseHandle(hFile);
				}
				else
				{
					wsprintf(szBuf, "Error %d opening bmark.exe\r\n", GetLastError());
					OutputDebugString(szBuf);
				}
			}
            ret = TRUE;
            break;

        case WM_COMMAND:
            ret = FALSE;
            break;

        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
            {
                DestroyWindow (hDlg);
                ret = TRUE;
            }
            else
            {
                ret = FALSE;
            }
            break;

            
        default:
            ret = FALSE;
            break;
    }
    
    return (INT_PTR) ret;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : SetDefaultSettings ()                                      *
 *                                                                          *
 *  PURPOSE    : Sets the application settings to default values.           *
 *                                                                          *
 ****************************************************************************/
VOID SetDefaultSettings(BmarkSettings& settings)
{
	settings.version.iMajor = bmarkApp.version.iMajor;
	settings.version.iMinor = bmarkApp.version.iMinor;
	char szBuf[MAX_PATH];
	GetTempPath(MAX_PATH, szBuf);
	settings.cDriveLetter = szBuf[0];
	settings.iNumPasses = 1;
	settings.iTestDuration = 10;
	settings.iDefaultBaseline = -1;
	settings.nBaselineFiles = 0;
	lstrcpy(settings.activationKey, "");
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : LoadSettings ()                                            *
 *                                                                          *
 *  PURPOSE    : Loads application settings from a file.                    *
 *                                                                          *
 ****************************************************************************/
VOID LoadSettings(TCHAR* lpszFileName)
{
	HANDLE hFile = CreateFile(lpszFileName, GENERIC_READ,
		FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwBytesRead;
		BmarkSettings settings;
		ReadFile(hFile, &settings, sizeof(BmarkSettings), &dwBytesRead, NULL);
		CloseHandle(hFile);
		if (settings.version.iMajor == bmarkApp.version.iMajor
			&& settings.version.iMinor == bmarkApp.version.iMinor
			&& dwBytesRead == sizeof(BmarkSettings))
		{
			bmarkApp.settings = settings;
		}
		else
		{
			MessageBox(NULL, "Could not load the settings file. Make sure the file is in a correct format. Please delete the file if it is corrupted.", "Error", MB_OK|MB_ICONINFORMATION);
		}
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : SaveSettings ()                                            *
 *                                                                          *
 *  PURPOSE    : Saves application settings to a file.                      *
 *                                                                          *
 ****************************************************************************/
VOID SaveSettings(TCHAR* lpszFileName)
{
	HANDLE hFile = CreateFile(lpszFileName, GENERIC_WRITE,
		FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwBytesWritten;
		WriteFile(hFile, &bmarkApp.settings, sizeof(BmarkSettings), &dwBytesWritten, NULL);
		CloseHandle(hFile);
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ExitPlugins ()                                             *
 *                                                                          *
 *  PURPOSE    : Allows plugin to free handles and exit gracefully.         *
 *                                                                          *
 ****************************************************************************/
VOID ExitPlugins()
{
	for (int i = 0; i < bmarkApp.nPlugins; i++)
	{
		// do plugin exit code here
		TDllPluginFunction func = (TDllPluginFunction)GetProcAddress(bmarkApp.plugins[i].hInst, "DllPluginFunction");
		if (func != NULL)
		{
			PluginData pluginData;
			pluginData.iValue = i;
			pluginData.pValue = &bmarkApp;
			func(BMARK_EXIT, &pluginData);
		}
	}
}


/****************************************************************************
 *                                                                          *
 *  FUNCTION   : SetupPlugins ()                                            *
 *                                                                          *
 *  PURPOSE    : Allows plugin to set itself up with the application.       *
 *                                                                          *
 ****************************************************************************/
VOID SetupPlugins()
{
	for (int i = 0; i < bmarkApp.nPlugins; i++)
	{
		// do plugin setup here
		TDllPluginFunction func = (TDllPluginFunction)GetProcAddress(bmarkApp.plugins[i].hInst, "DllPluginFunction");
		if (func != NULL)
		{
			PluginData pluginData;
			pluginData.iValue = i;
			pluginData.pValue = &bmarkApp;
			func(BMARK_SETUP, &pluginData);
		}
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CreateBenchmarkMenu ()                                     *
 *                                                                          *
 *  PURPOSE    : Creates a new (empty) menu and appends it the "Benchmark"  *
 *               menu items. It inserts this menu into the main menu bar.   *
 *                                                                          *
 ****************************************************************************/
VOID CreateBenchmarkMenu()
{
	HMENU hBmarkMenu = NULL;

	hBmarkMenu = CreateMenu();
	if (!hBmarkMenu) {
		return;
	}

	if (bmarkApp.navCount > 0)
	{
		UINT nOrdinal = 0;
		for (int i = 0; i < bmarkApp.navCount; i++)
		{
			AppendMenu(hBmarkMenu, MF_STRING, IDM_BENCHMARK + nOrdinal, bmarkApp.plugins[nOrdinal].nav.lpszTitle);
			nOrdinal++;
		}
		AppendMenu(hBmarkMenu, MF_SEPARATOR, -1, "");
	}

	if(!AppendMenu(hBmarkMenu, MF_STRING, IDM_EXIT, "E&xit"))
	{
		DestroyMenu(hBmarkMenu);
		return;
	}

	HMENU hMainMenu = GetMenu(bmarkApp.hMainWnd);
	InsertMenu(hMainMenu, 0, MF_POPUP|MF_BYPOSITION, (DWORD_PTR)hBmarkMenu, "&Benchmark");
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ShowTrialMessage ()                                        *
 *                                                                          *
 *  PURPOSE    : Show start-up message box for trial users                  *
 *                                                                          *
 ****************************************************************************/
VOID ShowTrialMessage()
{
	if (!ValidateKey(bmarkApp.settings.activationKey))
	{
		int result = MessageBox(bmarkApp.hMainWnd, "Welcome. You are now using the full-featured trial version of Dacris Benchmarks. To get rid of this message, activate by going to Tools - Activation. Do you wish to activate now?", "Activation Reminder", MB_YESNO|MB_ICONQUESTION);
		if (result == IDYES)
		{
			 /* Show Activation... dialog */
			 DialogBox (bmarkApp.hInst,
				 TEXT("ActivationDlg"),
				 bmarkApp.hMainWnd,
				 ActivationDialogProc);
		}
	}
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : BmarkWindowProc (hWnd, message, wParam, lParam)            *
 *                                                                          *
 *  PURPOSE    : Window function for the main app. window. Processes all the*
 *               menu selections and other messages.                        *
 *                                                                          *
 ****************************************************************************/
LRESULT CALLBACK BmarkWindowProc (
        HWND hWnd,
        UINT message,
        WPARAM wParam,
        LPARAM lParam )

{
    HMENU hMenu   = NULL;
    RECT  rc      = {0};
    POINT pt      = {0};
    BOOL  bRetDWP = FALSE;
	PluginData pluginData;

    switch (message)
    {
        case WM_SYSCOMMAND:
            /* Show the About ... dialog */
            if (wParam == ID_ABOUT)
            {
                DialogBox (bmarkApp.hInst,
                           TEXT("AboutBox"),
                           hWnd,
                           AboutDialogProc);
                break;
            }
            else
            {
                bRetDWP = TRUE;
                goto exit_func;
            }

		case WM_TIMER:
			// LOWORD added for portability
			switch (LOWORD(wParam))
			{
				case ID_SPLASHCLOSE:
					DestroyWindow (bmarkApp.hStartupDlg);
					bmarkApp.hStartupDlg = NULL;
					KillTimer(bmarkApp.hMainWnd, ID_SPLASHCLOSE);
					ShowTrialMessage();
					break;
			}
			break;

        case WM_COMMAND:
            // LOWORD added for portability
            switch (LOWORD(wParam))
            {
                 case IDM_EXIT:
					DestroyWindow (hWnd);
					break;

                 case IDM_ABOUT:
					/* Bring up the About.. dialog box */
					DialogBox (bmarkApp.hInst,
						TEXT("AboutBox"),
						hWnd,
						AboutDialogProc);
					break;
				 
				 case IDM_OPTIONS:
					/* Show Options... dialog */
					DialogBox (bmarkApp.hInst,
						TEXT("OptionsDlg"),
						hWnd,
						OptionsDialogProc);
					break;
					
				 case IDM_BASELINES:
					 /* Show Baselines... dialog */
					 DialogBox (bmarkApp.hInst,
						 TEXT("BaselineDlg"),
						 hWnd,
						 BaselineDialogProc);
					 break;

				 case IDM_ACTIVATION:
					 /* Show Activation... dialog */
					 DialogBox (bmarkApp.hInst,
						 TEXT("ActivationDlg"),
						 hWnd,
						 ActivationDialogProc);
					 break;

				 case IDM_HELPTOPICS:
					/* Start HTML Help */
					ShellExecute(bmarkApp.hMainWnd,
						NULL, "Bmark6.chm", NULL,
						NULL, SW_SHOWDEFAULT);
					break;

				 case IDM_SYSINFO:
					pluginData.iValue = BMARK_NAV_SYSINFO;
					pluginData.pValue = NULL;
					AppMessage(&(bmarkApp.appData), &pluginData);
					break;

				 case IDM_HTML:
					pluginData.iValue = BMARK_NAV_RESULTS;
					pluginData.pValue = NULL;
					AppMessage(&(bmarkApp.appData), &pluginData);
					break;
				 
				 case IDM_SYSINFOBROWSER:
					ShowSysInfoHTML(FALSE);
					break;

				 case IDM_HTMLBROWSER:
					ShowResultsHTML(FALSE);
					break;

				 case IDM_EXCEL:
					ShowResultsExcel();
					break;
            }
			if (LOWORD(wParam) >= IDM_BENCHMARK)
			{
				int idx = LOWORD(wParam) - IDM_BENCHMARK;
				if (idx < bmarkApp.nPlugins && bmarkApp.plugins[idx].hInst != 0)
				{
					if (!bmarkApp.isTestRunning)
					{
						// plugin must set isTestRunning to TRUE
						TDllPluginFunction func = (TDllPluginFunction)GetProcAddress(bmarkApp.plugins[idx].hInst, "DllPluginFunction");
						if (func != NULL)
						{
							PluginData pluginData;
							pluginData.iValue = idx;
							pluginData.pValue = &(bmarkApp.settings);
							func(BMARK_EXEC, &pluginData);
						}
					}
					else
					{
						OutputDebugString("User started a test while another test is already running.");
					}
				}
			}
            break;

		case WM_PAINT:
			{
				PAINTSTRUCT ps;
				BeginPaint(hWnd,&ps);
				FillRect(ps.hdc,&ps.rcPaint,(HBRUSH)GetStockObject(WHITE_BRUSH));
				EndPaint(hWnd,&ps);
				return 0;
			}

        case WM_CREATE:
            /* Create the browser control */
			bmarkApp.hWebWnd = CreateWindow(
				WEBFORM_CLASS,
				_T("about:blank"),
				WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE|WS_VSCROLL,
				0,0,100,100,hWnd,(HMENU)103,bmarkApp.hInst,0);
			PluginData pluginData;
			pluginData.iValue = BMARK_NAV_WELCOME;
			pluginData.pValue = NULL;
			AppMessage(&(bmarkApp.appData), &pluginData);

			/* Create the benchmark menu */
			bmarkApp.hMainWnd = hWnd;
			CreateBenchmarkMenu();

			/* Additional plug-in setup code */
			SetupPlugins();

			/* We're done. Set a timer to destroy splash screen. */
			SetTimer(bmarkApp.hMainWnd, ID_SPLASHCLOSE, 200, (TIMERPROC)NULL);

            break;

		case WM_SIZE:
			MoveWindow(bmarkApp.hWebWnd,0,0,LOWORD(lParam),HIWORD(lParam),TRUE);
            if (lParam)
            {
                /* If window is being sized to a non zero value...
                 * invalidate it's client area.
                 */
                InvalidateRect (hWnd, NULL, TRUE);
            }
			break;

		case WM_DESTROY:
			DestroyWindow(bmarkApp.hWebWnd);
            PostQuitMessage (0);
            break;

        default:
            bRetDWP = TRUE;
            goto exit_func;
            break;
    }

exit_func:
    if (bRetDWP)
    {
        return DefWindowProc (hWnd, message, wParam, lParam);
    }
    else
    {
        return 0;
    }
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : BmarkInit (hInstance)                                       *
 *                                                                          *
 *  PURPOSE    : Registers the main window class.                           *
 *                                                                          *
 *  RETURNS    : TRUE   -  if RegisterClass() went off ok                   *
 *               FALSE  -  otherwise.                                       *
 *                                                                          *
 ****************************************************************************/
BOOL BmarkInit (
    HINSTANCE hInstance )
{
    WNDCLASSEX wc = {0};
	ZeroMemory(&wc,sizeof(wc));
	wc.cbSize = sizeof(WNDCLASSEX);
	
	BOOL res = GetClassInfoEx(hInstance,_T("bmarkClass"),&wc);
	if (!res)
	{
		wc.lpfnWndProc   = (WNDPROC) BmarkWindowProc;
		wc.style         = CS_HREDRAW | CS_VREDRAW;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = hInstance;
		wc.hIcon         = LoadIcon (hInstance, MAKEINTRESOURCE(1001));
		wc.hIconSm       = NULL;
		wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
		wc.hbrBackground = NULL;
		wc.lpszMenuName  = TEXT("BmarkMenu");
		wc.lpszClassName = TEXT("bmarkClass");
	}
    return RegisterClassEx (&wc);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : OnExit(BOOL)                                               *
 *                                                                          *
 *  PURPOSE    : Detaches from plug-ins, frees up resources.                *
 *                                                                          *
 ****************************************************************************/
void OnExit(BOOL bSuccess)
{
	if (bmarkApp.hStartupDlg != NULL)
	{
		DestroyWindow (bmarkApp.hStartupDlg);
		bmarkApp.hStartupDlg = NULL;
	}
	if (bSuccess)
	{
		SaveSettings(SETTINGS_FILE);
		SaveBaseline(RESULTS_FILE);
	}
	else
	{
		//TODO: Log this event as error
		MessageBox(NULL, "An error occurred. The program is shutting down.",
			"Error", MB_ICONINFORMATION|MB_OK);
	}
	ExitPlugins();
	AppDetach(&(bmarkApp.appData));
	UnregisterClass("bmarkClass", bmarkApp.hInst);
	OleUninitialize();
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : WinMain (HINSTANCE, HINSTANCE, LPSTR, int)                 *
 *                                                                          *
 *  PURPOSE    : Creates the main app. window, calls an initialization      *
 *               function and enters the message loop.                      *
 *                                                                          *
 ****************************************************************************/
int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR     lpCmdLine,
    int       nCmdShow )
{
    HWND hWnd = NULL;
    MSG  msg = {0};   /* message */
    BOOL bRet = FALSE;
    BOOL bSuccess = TRUE;

	bmarkApp.version.iMajor = 6;
	bmarkApp.version.iMinor = 0;
	bmarkApp.hInst = hInstance;
	bmarkApp.isTestRunning = FALSE;
	bmarkApp.navCount = 0;
	bmarkApp.currentBaseline.nResults = 0;

	InitCommonControls();

	OleInitialize(0);

	/* Bring up the Startup dialog box */
	if (!IsWindow(bmarkApp.hStartupDlg))
	{
		bmarkApp.hStartupDlg = CreateDialog (hInstance,
			  TEXT("StartupDlg"),
			  NULL,
			  StartupDialogProc);

		if (!bmarkApp.hStartupDlg)
		{
			OnExit(FALSE);
			return 1;
		}

		ShowWindow(bmarkApp.hStartupDlg, SW_SHOWNORMAL);
		UpdateWindow(bmarkApp.hStartupDlg);
	}

	SetDefaultSettings(bmarkApp.settings);
	LoadSettings(SETTINGS_FILE);

	/* Set baseline version info. */
	bmarkApp.currentBaseline.version.iMajor = bmarkApp.version.iMajor;
	bmarkApp.currentBaseline.version.iMinor = bmarkApp.version.iMinor;

	/* Load baseline as current. */
	LoadBaselineAsCurrent(RESULTS_FILE);

	/* Set default description. */
	GetSysInfo(bmarkApp.currentBaseline.description, MAX_DESC);

	/* Load selected baseline as reference. */
	if (bmarkApp.settings.iDefaultBaseline >= 0
		&& bmarkApp.settings.iDefaultBaseline < bmarkApp.settings.nBaselineFiles)
	{
		LoadBaselineAsReference(bmarkApp.settings.baselineFiles[bmarkApp.settings.iDefaultBaseline].szFilename);
	}

	if (!BmarkInit (hInstance))
    {
        OnExit(FALSE);
		return 1;
    }

	// Create PluginSetup Application
	bmarkApp.appData.pValue = (void*)&AppMessageFunction;
	bmarkApp.appData.iValue = 1;
	AppAttach(&(bmarkApp.appData));
	
	HMODULE *dllModules = GetDllModules();
	bmarkApp.nPlugins = GetNumDllModules();
	for (int i = 0; i < bmarkApp.nPlugins; i++)
	{
		bmarkApp.plugins[i].hInst = dllModules[i];
	}

	/* Create the app. window */
    hWnd = CreateWindowEx(0,TEXT("bmarkClass"),
                         TEXT("Dacris Benchmarks"),
                         WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
                         CW_USEDEFAULT, CW_USEDEFAULT,
                         560, 400,
                         NULL, NULL, hInstance, NULL);

    if (!hWnd)
    {
		OnExit(FALSE);
		return 1;
    }

	bmarkApp.hMainWnd = hWnd;

    ShowWindow (hWnd, nCmdShow);
    UpdateWindow (hWnd);

    while (bRet = GetMessage (&msg, NULL, 0, 0) != 0)
    {
        if (bRet == -1)
        {
            OnExit(FALSE);
			return 1;
        }
        else
        {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
    }

	OnExit(TRUE);
	return 0;
}

